home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
La Traviata
/
La Traviata.iso
/
viewer
/
pixit.arc
/
GIFDCD.C
next >
Wrap
Text File
|
1989-04-14
|
12KB
|
427 lines
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define PSZ 768 /* Maximum palette size */
#define BSZ 16384 /* Size of write buffer for delzw() */
struct gifhead {
char s[6];
unsigned int w, h;
unsigned char c, b, z;
};
struct image {
unsigned int l, t, w, h;
unsigned char m;
};
int _readc(int f)
/* Read a character from file f, return -1 on end of file */
{
unsigned char c;
if (_read(f, &c, 1) == 1)
return c;
else
return -1;
}
long delzw(int g, int h, int n)
/* Decompress a .GIF style LZW compressed data stream of n-bit symbols,
getting codes from file g and writing symbols (one per byte) to file
h. delzw() returns the number of bytes written to file h. n must be
in the range 2..8. */
{
int n2, /* 2^n */
m, /* Current code size in bits */
m2, /* 2^m */
k, /* Next available table entry */
c, /* Code being expanded */
f, /* Last symbol decoded */
i, /* Code just read */
d, /* Code read before this one */
j, /* Number of bits left in *p */
a; /* Bytes in next block */
unsigned char *p, /* Pointer to current byte in read buffer */
*q, /* Pointer past liast byte in read buffer */
b[255], /* Read buffer */
*u, /* Stack pointer into r */
r[4096], /* Stack for code expansion */
s[4096]; /* Symbol entries in table */
int t[4096]; /* Code entries in table */
unsigned char *w; /* Write buffer pointer */
unsigned char y[BSZ]; /* Write buffer */
long e; /* Count of bytes written */
static int z[] = {0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff,
0x7ff,0xfff,0x1fff,0x3fff,0x7fff};
/* Initialize buffers */
w = y;
e = 0;
p = q = b;
j = 8;
/* Setup decompression parameters */
if (n < 2 || n > 8)
return -5; /* Bad symbol size */
n2 = 1 << n;
k = n2 + 2;
m2 = 1 << (m = n + 1);
f = d = -1; /* There is no old code yet */
/* Do until termination code (2^n + 1) is read */
while (1)
{
/* Get next code: reads next m bits from file g, which is made of
blocks of 1..255 bytes, each preceded by a one byte count. */
if (j == 8)
{
if (++p >= q &&
(((a = _readc(g)) < 1) ||
(q = (p = b) + _read(g, b, a)) < b + a))
return -4; /* Premature end of file */
j = 0;
}
c = *p;
if ((i = m + j) <= 8)
{
*p >>= m;
j = i;
}
else
{
if (++p >= q &&
(((a = _readc(g)) < 1) ||
(q = (p = b) + _read(g, b, a)) < b + a))
return -4; /* Premature end of file */
c |= *p << (8 - j);
if (i <= 16)
*p >>= (j = i - 8);
else
{
if (++p >= q &&
(((a = _readc(g)) < 1) ||
(q = (p = b) + _read(g, b, a)) < b + a))
return -4; /* Premature end of file */
c |= *p << (16 - j);
*p >>= (j = i - 16);
}
}
c &= z[m];
i = c;
/* Check code */
if (c == n2 + 1)
break; /* Terminator symbol */
if (c > k)
return -3; /* Bad code */
/* See if clear code */
if (c == n2)
{
k = n2 + 2;
m2 = 1 << (m = n + 1);
f = d = -1;
continue;
}
/* Empty stack */
u = r;
/* Check for special case---if code is next code to be defined */
if (c == k)
{
if (d == -1)
return -2; /* First code is not a symbol */
*u++ = f;
c = d;
}
/* Build string backwards */
while (c >= n2)
{
*u++ = s[c];
c = t[c];
}
/* Write string out forwards, update final character (f) */
f = c;
do {
*w++ = c;
if (w == y + BSZ)
{
_write(h, y, BSZ);
e += BSZ;
w = y;
}
if (u <= r)
break;
c = *--u;
} while (1);
/* Put new entry in table, update code length, old code */
if (k < 4096 && d != -1)
{
t[k] = d;
s[k] = f;
if (++k >= m2 && m < 12)
m2 = 1 << ++m;
}
d = i;
}
/* Check that termination code was in the last byte of data */
if (_readc(g) != 0)
return -1; /* File didn't end after terminator */
/* Flush write buffer and return bytes written */
if (w - y)
{
_write(h, y, w - y);
e += w - y;
}
return e;
}
void gif(int f, int w, int e)
/* Decode .gif file f: if e is 1, do an extended decode, of e is 2,
write a decompressed version of the .gif file to file w. */
{
long n, t;
int b, c;
struct gifhead g;
struct image d;
unsigned char p[PSZ];
/* Check GIF header */
if (_read(f, &g, sizeof(g)) != sizeof(g) ||
strncmp(g.s, "GIF87a", 6))
printf(" is not a GIF87a file.\n");
else
{
/* Show header information */
printf(" is %dx%dx%d bits and %d bits/color with ",
g.w, g.h, (g.c & 7) + 1, ((g.c >> 4) & 7) + 1);
if (g.c & 0x80)
printf("a ");
else
printf("no ");
printf("global color map\n");
if ((g.c & 8) || g.z)
printf(" !reserved bits were not all zero\n");
/* If extended decode, read entire file */
if (e)
{
/* Show one more detail from header */
printf(" background color is %d\n", g.b);
/* If /w, write crucial header information */
if (e == 2)
{
_write(w, "PX", 2);
_write(w, &(g.w), 6);
}
/* Global color table is next */
if (g.c & 0x80)
{
c = 3 * (1 << ((g.c & 7) + 1));
if (e != 2)
{
if (lseek(f, c, SEEK_CUR) == -1L)
{
printf(" !file stopped in global color table\n");
return;
}
}
else /* Save global color table in p */
{
if (_read(f, p, c) != c)
{
printf(" !file stopped in global color table\n");
return;
}
for (b = 0; b < c; b++)
p[b] >>= 2;
for (; b < PSZ; b++)
p[b] = 0;
}
}
else
printf(" !no global color table---.pix file unusable\n");
/* Read images and extension blocks */
while ((c = _readc(f)) == ',' || c == '!')
/* Process image */
if (c == ',')
{
/* Initialize bits per pixel */
b = (g.c & 7) + 1;
/* Read image descriptor */
if (_read(f, &d, sizeof(d)) != sizeof(d))
{
printf(" !file stopped in image descriptor\n");
return;
}
printf(" image: start %d/%d pixels from left/top,",
d.l, d.t);
printf(" is %dx%d %s\n",
d.w, d.h, d.m & 0x40 ? "interlaced" : "sequential");
if (d.m & 0x38)
printf(" !reserved bits were not all zero\n");
if (e == 2)
{
if (d.l || d.t || d.w != g.w || d.h != g.h || (d.m & 0x40))
printf(" !image not standard---.pix file unusable\n");
_write(w, &d, 8);
_write(w, p, PSZ);
}
/* Local color map (if any) is next */
if (d.m & 0x80)
{
b = (d.m & 7) + 1;
printf(" local color map with %d bits/pixel\n", b);
if (lseek(f, 3 * (1L << b), SEEK_CUR) == -1L)
{
printf(" !file stopped in local color map\n");
return;
}
if (e == 2)
printf(" !has local color map---.pix file unusable\n");
}
/* Get bits per symbol for compressed image */
if ((c = _readc(f)) == -1)
{
printf(" !file stopped in raster data\n");
return;
}
printf(" code size = %d bits\n", c);
/* Go over image blocks if just /e */
if (e != 2)
{
n = t = 0;
while ((c = _readc(f)) != 0)
{
if (c == -1 || lseek(f, c, SEEK_CUR) == -1L)
{
printf(" !file stopped in raster data block\n");
return;
}
n++;
t += c;
}
printf(" compressed image = %ld bytes in %ld blocks\n",
t, n);
}
/* If /w, decompress image and write it out */
else
if ((t = delzw(f, w, c)) < 0)
printf(" !error %ld decompressing image\n", t);
else
printf(" decompressed image = %ld pixels\n", t);
}
/* Process extension block */
else
{
if ((c = _readc(f)) == -1)
{
printf(" !file stopped in extension block\n");
return;
}
printf(" gif extension block with function code %d\n", c);
n = t = 0;
while ((c = _readc(f)) != 0)
{
if (c == -1 || lseek(f, c, SEEK_CUR) == -1L)
{
printf(" !file stopped in extension data block\n");
return;
}
n++;
t += c;
}
printf(" total extension data = %ld bytes in %ld blocks\n",
t, n);
}
/* Make sure images and extensions terminated with a semicolon */
if (c == ';')
printf(" file");
else
printf(" !file not");
printf(" properly terminated");
/* See if hit end of file */
if (eof(f) != 1)
printf(" (but extra data at end)");
/* Done reading file */
printf("\n\n");
}
}
/* Close files */
_close(f);
if (e == 2)
_close(w);
}
void main(int argc, char *argv[])
/* Process .gif files and options---only options allowed are /e for an
extended decode, and /w for a full decompression, writing the results
to the same filename, but with extension .pix. */
{
int i, e, f, w;
char a[128];
e = 0; /* Extended list off */
for (i = 1; i < argc; i++)
if (argv[i][0] == '/')
if ((argv[i][1] & 0x5f) == 'E')
e = 1; /* Extended list on */
else if ((argv[i][1] & 0x5f) == 'W')
e = 2; /* Write image data */
else
printf("(invalid option)\n");
else
{
printf(argv[i]);
strcat(strcpy(a, argv[i]), ".gif");
if ((f = _open(a, O_RDONLY)) == -1)
printf(".gif not found.\n");
else
{
if (e == 2)
{
strcat(strcpy(a, argv[i]), ".pix");
if ((w = _creat(a, 0)) == -1)
{
printf(".pix could not be created---downgrading to /e\n");
e = 1;
printf(argv[i]);
}
}
gif(f, w, e);
}
}
}